// Copyright (C) 2008 Taylor L. Riche <riche@cs.utexas.edu>
//  
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software 
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//

package frontend;


import appcomp.*;
import appcomp.entities.*;
import syscomp.*;
import core.*;
import profcomp.*;
import profcomp.entities.*;
import appcomp.pathfinder.*;
import java.util.ArrayList;
import java.util.Map;
import java.io.FileReader;
import java.lang.Exception;
import com.javadude.antxr.scanner.BasicCrimsonXMLTokenStream;

/**
 * @author riche
 *
 */
public class Main {

	/**
	 * Main starting method of application. Will compile system model or 
	 * programming model based on option switches given in args.
	 * @param args The option switch and file name to be compiled.
	 */
	public static void main(String[] args) throws Exception {
		
		BasicCrimsonXMLTokenStream stream = null;
		
		if (args[0].equals("--app")) {
			try {
				stream = new BasicCrimsonXMLTokenStream(new FileReader(args[1]), AppParser.class, false, false);
			}
			catch (Exception e) {
				System.err.println(e.getMessage());
				System.exit(1);
			}
			// Create AppParser

			try {
				AppParser appParser = new AppParser(stream);
				appParser.document(ParserFunc.GENCODE);
			}
			catch (Exception e) {
				System.err.println(e.getMessage());
				System.exit(1);
			}
		}
		else if (args[0].equals("--final")) {
			Map<String, OperatorInfo> oiMap = null;
			try {
				stream = new BasicCrimsonXMLTokenStream(new FileReader(args[1]), ProfParser.class, false, false);
			}
			catch (Exception e) {
				System.err.println(e.getMessage());
				System.exit(1);
			}
			ProfParser profParser = new ProfParser(stream);
			try {
				oiMap = profParser.document();
			}
			catch (Exception e) {
				System.err.println(e.getMessage());
				System.exit(1);
			}
//			for(OperatorInfo oi : oiMap.values()) {
//				System.out.println(oi.getName());
//				oi.printPorts();
//			}
			String appName = null, sysName = null;
			try {
				stream = new BasicCrimsonXMLTokenStream(new FileReader(args[2]), AppParser.class, false, false);
			}
			catch (Exception e){
				System.err.println(e.getMessage());
				System.exit(1);
			}
			// Create AppParser

			AppParser appParser = new AppParser(stream);
			try {
				appName = appParser.document(ParserFunc.GETENTS);
			}
			catch (Exception e) {
				System.err.println(e.getMessage());
				e.printStackTrace();
				System.exit(1);
			}
			for (Operator o : appParser.getOpList()) {
				if(!o.doesGenerate()) {
					String opName = o.getName();
					OperatorInfo opInfo = oiMap.get(opName);
					for (Port p : o.getPortList()) {
						if(p.getDirection() == Port.Direction.IN) {
							PortInfo pi = opInfo.lookupPort(p.getName());
							o.setDelay(p.getName(), pi.getValue());
						}
					}
				}
			}
			Pathfinder pf = new Pathfinder();
			int listSize = appParser.getOpList().size();
			for (Operator o : appParser.getOpList()) {
				System.out.print(o.getName());
				if(o.doesGenerate()) {
					int pathcount = pf.findPaths(o);
					System.out.println(pathcount);
				}
				else {
					System.out.println();
				}
			}
			pf.printPaths();
			for(Path p : pf.getMasterPathList()) {
				double slack = p.getSlack(appParser.getDelayGuarantee());
				p.distributeSlack(slack);
			}
			for(Operator o : appParser.getOpList()) {
				o.translateSlack();
			}
			CodeGenerator cg = new CodeGenerator();
			cg.registerEntities(appParser.getOpList());
			cg.generateEntities(appParser.getOpList());
		}
		else if (args[0].equals("--prof")) {
			String appName = null, sysName = null;
			try {
				stream = new BasicCrimsonXMLTokenStream(new FileReader(args[1]), AppParser.class, false, false);
			}
			catch (Exception e){
				System.err.println(e.getMessage());
				System.exit(1);
			}
			// Create AppParser

			AppParser appParser = new AppParser(stream);
			try {
				appName = appParser.document(ParserFunc.GETNAME);
			}
			catch (Exception e) {
				System.err.println(e.getMessage());
				e.printStackTrace();
				System.exit(1);
			}
			try {
				stream = new BasicCrimsonXMLTokenStream(new FileReader(args[2]), SysParser.class, false, false);
			}
			catch (Exception e) {
				System.err.println(e.getMessage());
				System.exit(1);
			}
			// Create SysParser

			try {
				SysParser sysParser = new SysParser(stream);
				sysName = sysParser.document(ParserFunc.GETNAME);
			}
			catch (Exception e) {
				System.err.println(e.getMessage());
				e.printStackTrace();
				System.exit(1);
			}
			CodeGenerator cg = new CodeGenerator();
			//cg.generateMain(appName, sysName);
			cg.generateProfiler(appName, sysName, appParser.getOpList());
		}
		else if (args[0].equals("--sys")) {
			try {
				stream = new BasicCrimsonXMLTokenStream(new FileReader(args[1]), SysParser.class, false, false);
			}
			catch (Exception e) {
				System.err.println(e.getMessage());
				System.exit(1);
			}
			// Create AppParser

			try {
				SysParser sysParser = new SysParser(stream);
				sysParser.document(ParserFunc.GENCODE);
			}
			catch (Exception e) {
				System.err.println(e.getMessage());
				e.printStackTrace(System.err);
				System.exit(1);
			}
		}
		else if (args[0].equals("--main")) {
			String appName = null, sysName = null;
			try {
				stream = new BasicCrimsonXMLTokenStream(new FileReader(args[1]), AppParser.class, false, false);
			}
			catch (Exception e){
				System.err.println(e.getMessage());
				System.exit(1);
			}
			// Create AppParser

			try {
				AppParser appParser = new AppParser(stream);
				appName = appParser.document(ParserFunc.GETNAME);
			}
			catch (Exception e) {
				System.err.println(e.getMessage());
				System.exit(1);
			}
			try {
				stream = new BasicCrimsonXMLTokenStream(new FileReader(args[2]), SysParser.class, false, false);
			}
			catch (Exception e) {
				System.err.println(e.getMessage());
				System.exit(1);
			}
			// Create SysParser

			SysParser sysParser = null;
			try {
				sysParser = new SysParser(stream);
				sysName = sysParser.document(ParserFunc.GETENTS);
			}
			catch (Exception e) {
				System.err.println(e.getMessage());
				System.exit(1);
			}
			CodeGenerator cg = new CodeGenerator();
			cg.generateMain(appName, sysName, sysParser.getMainPGList());
		}
		else if (args[0].equals("--all")) {
			String appName = null, sysName = null;
			try {
				stream = new BasicCrimsonXMLTokenStream(new FileReader(args[1]), AppParser.class, false, false);
			}
			catch (Exception e){
				System.err.println(e.getMessage());
				System.exit(1);
			}
			// Create AppParser
			try {
				AppParser appParser = new AppParser(stream);
				appName = appParser.document(ParserFunc.GENCODE);
			}
			catch (Exception e) {
				System.err.println(e.getMessage());
				System.exit(1);
			}
			try {
				stream = new BasicCrimsonXMLTokenStream(new FileReader(args[2]), SysParser.class, false, false);
			}
			catch (Exception e) {
				System.err.println(e.getMessage());
				System.exit(1);
			}
			// Create AppParser

			try {
				SysParser sysParser = new SysParser(stream);
				sysName = sysParser.document(ParserFunc.GENCODE);
			}
			catch (Exception e) {
				System.err.println(e.getMessage());
				System.exit(1);
			}
			CodeGenerator cg = new CodeGenerator();
			cg.generateMain(appName, sysName);
		}
		else {
			System.err.println("Command not found!");
			System.exit(1);
		}
	}

}
